package br.com.srv.service;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Date;
import java.util.List;
import java.util.Map;

import br.com.srv.teste.ServerReceiver;

public class FFThread implements Runnable {
	
	/**
	 * Timeout para fechar conexão. 
	 */
	public static int TEMPO_MAXIMO_SEM_TRANSMISAO = 1800;
	
	private final int TAMANHO_MINIMO = 3;
	
	private final String COMM_AT = "AT";
	private final String COMM_GPS = "+++";
	private final String SEPARADOR = "|";
	
	/**
	 * Classe que executa o processamento dos dados.
	 */
	private ClasseServico classeServico;
	
	private String serialVeiculo;
	private Socket conexao;
	InputStream inputStream;
	OutputStream outputStream;
	private int count = 1;
	
	
	
	public FFThread(Socket conexao) {
		this.conexao = conexao;
		try {
			inputStream = conexao.getInputStream();
			outputStream = conexao.getOutputStream();
			
			
			classeServico = new ClasseServicoImpl();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void run() {
		try {
			
			byte[] bytes = null;
			
			String msgFinal = "OK";
			
			while(!conexao.isClosed() && count < TEMPO_MAXIMO_SEM_TRANSMISAO) {
				
				try {
					int sizeBytes = inputStream.available();
					bytes = new byte[sizeBytes];
	
					msgFinal = "OK";
					
					//Verificar se possui tamanho minimo
					if(sizeBytes > 0 && sizeBytes < TAMANHO_MINIMO) {
						inputStream.read(bytes);
						msgFinal = "ERRO";					
					} else if((sizeBytes >= TAMANHO_MINIMO)) {
						inputStream.read(bytes);
					
						String mensagem = new String(bytes);
						System.out.println(new Date() + " " + serialVeiculo + " " + mensagem);
						
						//cancelar thread se chegar comando AT		
						if (mensagem.substring(0, 2).equals(COMM_AT)) {
							System.out.println("Comando AT, fechar conexão com veiculo: " + getSerialVeiculo());
							conexao.close();
							ServerReceiver.decrementarContador();
						} else if (mensagem.substring(0, 3).equals(COMM_GPS)) {
							msgFinal = "";
						} else if (!mensagem.substring(0, 3).equals(COMM_GPS)) {
							
							mensagem = mensagem.replace('|', '@');
							
							//Separa a String em sub strings com os dados
							//obs.: funciona para o caso dos dumps
							String subMensagens[] = mensagem.split("@");
							
							
							for (String subMensagem : subMensagens) {
								subMensagem += "|";
								System.out.println(new Date() + " :: " + subMensagem);
								if (subMensagem.charAt(subMensagem.length()-1) == '|') {
									msgFinal = tratarMensagem(subMensagem);
									
									//Verifica se o comando realmente chegou correto no veiculo
									verificarAck(msgFinal);
									msgFinal = "OK";
									
								} else {
									msgFinal = "ERRO";
									break;
								}
							}
							
						} else {
							System.out.println("aqui!");
							msgFinal = "ERRO";						
						}
						
						//zerar contador
						count = 0;
						
						enviarDado(msgFinal);
					} else {
						count++;
						Thread.sleep(100L);
					}
				} catch (Exception e) {
					enviarDado("ERRO");
					e.printStackTrace();
				}
			}
			
			ServerReceiver.decrementarContador();
			
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
			System.out.println(e.getStackTrace());
		} finally {
			try {
				System.out.println("fechando... " + getSerialVeiculo());
				inputStream.close();
				outputStream.close();
			} catch (Exception e) {
				System.out.println("dentro do finally");
			}
		}
	}
	

	private void verificarAck(String msgFinal) throws IOException,
			InterruptedException {
		byte[] bytes;
		int sizeBytes;
		if (msgFinal.length() > 3) {
			
			int count = 0;
			while (count < 15) {
				
				if ( inputStream.available() > 1 ) {											
					sizeBytes = inputStream.available();
					bytes = new byte[sizeBytes];
					inputStream.read(bytes);
					String ack = new String(bytes);
					
					//retirar o +++
					ack = ack.substring(0, 1+ack.indexOf('#'));
					
					if (msgFinal.equals(ack)) {
						System.out.println("valeu!");
					} else {
						System.out.println("não valeu!");
					}
					break;
				}
				
				Thread.sleep(1000);
				count++;
				
			}
		}
	}

	private String tratarMensagem(String mensagem)
			throws IOException {
		String msgFinal = "OK";
		
		if (mensagem.charAt(mensagem.length()-1) == SEPARADOR.charAt(0)) {
			try {
				
				//Retirar o separador
				mensagem = mensagem.replace(SEPARADOR.charAt(0), '\r');
				
				List<Map<String, String>> listaComando = getClasseServico().processarCoordenadas(mensagem);
				
				if (!listaComando.isEmpty()) {
					for (Map<String, String> map : listaComando) {
						
						String comando = "@"+map.get("CMD_DESC") + "#";
						
						enviarDado(comando);
						getClasseServico().setarComandoComoEnviado(map.get("ID"));
						msgFinal = comando;
					}
				}

			} catch (Exception e) {
				msgFinal = "ERRO";
				e.printStackTrace();
			}
		} else {
			msgFinal = "ERRO";
		}
		
		return msgFinal;
	}

	private void enviarDado(String msgFinal) throws IOException {
		
		if (!msgFinal.equals("")) {
			msgFinal += "\r\n";
			System.out.println(new Date() + " " + serialVeiculo + " :: mensagem retorno: " + msgFinal);
			outputStream.write((msgFinal).getBytes());
			outputStream.flush();
		}
	}	

	public String getSerialVeiculo() {
		return serialVeiculo;
	}

	public void setSerialVeiculo(String serialVeiculo) {
		this.serialVeiculo = serialVeiculo;
	}

	public Socket getConexao() {
		return conexao;
	}

	public void setConexao(Socket conexao) {
		this.conexao = conexao;
	}

	public ClasseServico getClasseServico() {
		return classeServico;
	}

	public void setClasseServico(ClasseServico classeServico) {
		this.classeServico = classeServico;
	}
	
}
